
#include <BMap>
#include <BFile>
#include "IGlobal.h"
#include "IFontFamily.h"

using namespace BWE;

const BStringArray& IFontFamily::GenericFamily(const BString& family)
{
	static BMap<BString, BStringArray> genericFamilyMap;
	return genericFamilyMap(family);
}
BString IFontFamily::SearchFileName(const BString& family)
{
	const char* fontExts[] = { "ttf","ttc","otf" };
	BString fileName;
	for (int e = 0; e < 3; e++)
	{
		const char* ext = fontExts[e];
		for (int i = 0; i < app_fontPaths.size(); i++)
		{
			fileName.reset();
			fileName << app_fontPaths[i] << '/' << family << '.' << ext;
			if (BFile::Exist(fileName))
				return fileName;
		}

		fileName.reset();
		fileName << "./font/" << family << '.' << ext;
		if (BFile::Exist(fileName))
			return fileName;

		fileName.reset();
		fileName << app_libPath << "/font/" << family << '.' << ext;
		if (BFile::Exist(fileName))
			return fileName;

		fileName.reset();
#ifdef _WIN32
		fileName << "C:/Windows/Fonts/";
#endif
#ifdef linux
		fileName << "/usr/share/fonts/";
#endif
		fileName << family << '.' << ext;
		if (BFile::Exist(fileName))
			return fileName;
	}
	return BString();
}

IFontFamily::IFontFamily(const BString& fileName)
{
	library = 0;
	face = 0;
	error = 0;
	this->fileName = fileName;
	open();
}
IFontFamily::~IFontFamily()
{

}

bool IFontFamily::open()
{
	if (fileName.empty())
		return false;

	if (FT_Init_FreeType(&library))
		return false;

	if (FT_New_Face(library, fileName.cstr(), 0, &face))
		return false;

	encodingList.clear();
	for (int i = 0; i < face->num_charmaps; i++)
	{
		FT_Encoding encode = face->charmaps[i]->encoding;
		switch (encode)
		{
		case FT_ENCODING_MS_SYMBOL:			encodingList.append(Encoding_MS_Symbol);		break;
		case FT_ENCODING_UNICODE:			encodingList.append(Encoding_Unicode);			break;
		case FT_ENCODING_GB2312:			encodingList.append(Encoding_GB2312);			break;
		case FT_ENCODING_BIG5:				encodingList.append(Encoding_Big5);				break;
		case FT_ENCODING_JOHAB:				encodingList.append(Encoding_Johab);			break;
		case FT_ENCODING_APPLE_ROMAN:		encodingList.append(Encoding_Apple_Roman);		break;
		}
	}
	if (encodingList.size())
	{
		changeEncoding(encodingList.first());
	}
	return true;
}
bool IFontFamily::close()
{
	if (!library || !face)
		return false;
	FT_Done_Face(face);
	FT_Done_FreeType(library);
	return true;
}

bool IFontFamily::changeEncoding(Encoding encoding)
{
	if (encodingList.contain(encoding))
	{
		if (encoding == Encoding_GB2312)
		{
			if (FT_Select_Charmap(face, FT_ENCODING_GB2312))
				return false;
			encode = encoding;
			return true;
		}
		if (encoding == Encoding_Unicode)
		{
			if (FT_Select_Charmap(face, FT_ENCODING_UNICODE))
				return false;
			encode = encoding;
			return true;
		}
	}
	return false;
}
bool IFontFamily::image(FT_ULong code, int size, CodeInfo& info)
{
	if (!library || !face)
		return false;

	int glyph_index = FT_Get_Char_Index(face, code);
	if (glyph_index == 0)
		return false;

	if (FT_Set_Pixel_Sizes(face, size, size))
		return false;

	if (FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT))
		return false;

	if (FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL))
		return false;

	FT_Bitmap bmp = face->glyph->bitmap;
	int width = bmp.width;
	int height = bmp.rows;
	BByte* buffer = bmp.buffer;
	if (width < 1 || height < 1)
		return false;

	FT_GlyphSlot glyph = face->glyph;
	info.left = glyph->bitmap_left;
	info.top = glyph->bitmap_top;
	info.advance = glyph->metrics.vertAdvance / 64;
	int bearingY = glyph->metrics.vertBearingY / 64;
	int bearingX = glyph->metrics.vertBearingX / 64;

	info.image = new BImage();
	info.image->setFormat(Format_Alpha);
	info.image->setSize(width, height);
	BByteArray* pixels = info.image->pixels();
	memcpy(pixels->data(), buffer, width * height);

	return true;
}
BGlyph* IFontFamily::glyph(FT_ULong code, CodeInfo& info)
{
	if (!library || !face)
		return 0;

	int glyph_index = FT_Get_Char_Index(face, code);
	if (glyph_index == 0)
		return 0;

	if (FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT))
		return 0;

	FT_GlyphSlot glyphslot = face->glyph;

	BGlyph* glyph = new BGlyph();
	return glyph;
}

